package cn.lovezsm.simulationsystem.service;

import cn.lovezsm.bjcjbase.bean.*;
import cn.lovezsm.bjcjbase.config.APConfig;
import cn.lovezsm.bjcjbase.config.LocationConfig;
import cn.lovezsm.bjcjbase.config.MessageConfig;
import cn.lovezsm.bjcjbase.data.DataParser;
import cn.lovezsm.bjcjbase.util.SpringUtils;
import cn.lovezsm.bjcjdao.DataCache;
import cn.lovezsm.bjcjdao.FileMessageDataBase;
import cn.lovezsm.locationsystem.algorithm.LocationAlgorithm;
import cn.lovezsm.simulationsystem.service.bean.SimulationResult;
import org.springframework.stereotype.Service;

import javax.xml.crypto.Data;
import java.io.*;
import java.util.*;

@Service
public class Simulator {

    public SimulationResult simulationByRawFile(Map<String,Object> simulationParams) {

        SimulationResult simulationResult = null;
        Map<Integer, List<LocationResult>> resultMap = new HashMap<>();

        //读取仿真参数
        File rawFile = (File) simulationParams.get("rawFile");
        LocationConfig locationConfig = (LocationConfig) simulationParams.get("locationConfig");
        if (locationConfig == null){
            locationConfig = LocationConfig.getDefault();
        }
        String fingerprintName = (String) simulationParams.get("fingerprintName");
        String avgFilePath = (String) simulationParams.get("avgFilePath");
        String stdFilePath = (String) simulationParams.get("stdFilePath");
        String gridFilePath = (String) simulationParams.get("gridFilePath");
        String gridName = (String) simulationParams.get("gridName");
        MessageConfig messageConfig = (MessageConfig) simulationParams.get("messageConfig");

        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(rawFile));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }
        FileMessageDataBase dataBase = new FileMessageDataBase(rawFile);
        Map<Long, List<Message>> messageMap = dataBase.getMessageMap();
        //设置定位参数

        APConfig apConfig = new APConfig();
        Set<AP> apList = new HashSet<>();
        apList.add(new AP("70476001a301",0,0,0));
        apList.add(new AP("70476001a302",0,0,1));
        apList.add(new AP("70476001a303",0,0,2));
        apList.add(new AP("70476002a301",0,0,3));
        apList.add(new AP("70476002a307",0,0,4));
        apList.add(new AP("70476002a308",0,0,5));
        apList.add(new AP("70476002a309",0,0,6));
        apList.add(new AP("70476002a310",0,0,7));
        apList.add(new AP("70476002a311",0,0,8));
        apList.add(new AP("70476002a312",0,0,9));
        apConfig.setApList(apList);

        Map<String,Object> locationParams = new HashMap<>();

        locationParams.put("locationConfig",locationConfig);
        locationParams.put("fingerPrint",FingerPrintBuilder.build(fingerprintName, new File(avgFilePath), new File(stdFilePath)));
        locationParams.put("gridMap",GridMap.buildByFile(new File(gridFilePath),gridName));
        locationParams.put("apConfig",apConfig);

        long firstDataTimestamp = Long.MAX_VALUE;
        long lastDataTimestamp = Long.MIN_VALUE;
        for(Map.Entry<Long,List<Message>> entry:messageMap.entrySet()){
            Long timeStamp = entry.getKey();
            if (timeStamp<firstDataTimestamp){
                firstDataTimestamp = timeStamp;
            }
            if (timeStamp>lastDataTimestamp){
                lastDataTimestamp = timeStamp;
            }
            List<Message> messageList = entry.getValue();
            entry.setValue(DataParser.messageFilter(messageConfig,messageList));
        }
        //Map<Long,List<Message>>  -->> Map<Integer,List<Message>>
        Map<Integer,List<Message>> ndata = conversionDataBase(messageMap,firstDataTimestamp,lastDataTimestamp,locationConfig.getSlidingWindow());
        String locationAlgorithmName = locationConfig.getLocationAlgorithmName();
        LocationAlgorithm locationAlgorithm = (LocationAlgorithm) SpringUtils.getBean(locationAlgorithmName);
        for (Map.Entry<Integer,List<Message>> entry:ndata.entrySet()){
            locationParams.put("data",entry.getValue());
            //执行定位操作
            List<LocationResult> locationResult = locationAlgorithm.locate(locationParams);
            resultMap.put(entry.getKey(),locationResult);
        }

        simulationResult = new SimulationResult(resultMap,firstDataTimestamp,lastDataTimestamp);
        double x = 30.25;
        double y = 3.75;
        for (Map.Entry<Integer,List<LocationResult>> entry:resultMap.entrySet()){
            Integer second = entry.getKey();
            List<LocationResult> value = entry.getValue();
            double error = 0;
            for (LocationResult result:value){
                error+=Math.sqrt(Math.pow(result.getPos().getX()-x,2)+Math.pow(result.getPos().getY()-y,2));
            }
            System.out.println("第"+second+"秒平均误差为："+(error/value.size()));
        }
        return simulationResult;
    }

    private Map<Integer,List<Message>> conversionDataBase(Map<Long, List<Message>> messageMap, long firstDataTimestamp, long lastDataTimestamp, Integer slidingWindow) {
        Map<Integer,List<Message>> ans = new HashMap<>();
        int time = (int) ((lastDataTimestamp-firstDataTimestamp)/1000+1);
        for (int i=1;i<=time;i++){
            ans.put(i,new ArrayList<>());
        }
        for (Map.Entry<Long,List<Message>> entry:messageMap.entrySet()){
            Long timestamp = entry.getKey();
            int curTime = (int) ((timestamp - firstDataTimestamp)/1000+1);
            for (int i = curTime;i<=time&&i<curTime+slidingWindow;i++){
                ans.get(i).addAll(entry.getValue());
            }
        }
        return ans;
    }

}
